import std.stdio, std.stream, std.string;
// gdc -o bacteria *.d && ./bacteria


void main (string[] argv)
{
	auto grille = new Grid ("map2");
	grille.setPossibleMoves(SquareState.p1);
	
	//void myOptArgs (string option, string value) {
	
	//}
	
	//writef("Saisir une action : ");
	
	while (true) {
		string buf;
		
		fprintf (stderr, "Client : Attente action...\n");
		readln (stdin, buf);
		
		fprintf (stderr, "Client : Traitement action...\n");
		//~ grille.puts;
		
		fprintf (stdout, toStringz(grille.toString));
		fprintf (stdout, "----------\n");
		fflush (stdout);
		//writef ("Saisir une action : ");
	}
}


class SquareState {
private :
	static SquareState[] states;
	char _symbol;
	char _savesymbol;
	bool _busy;

public :
	// singleton generators
	static SquareState empty () {
		static SquareState singleton = null;
		if (singleton is null) {
			singleton = new SquareState (false, '-', '-');
			states ~= singleton;
		}
		return singleton;
	}
	
	static SquareState hole () {
		static SquareState singleton = null;
		if (singleton is null) {
			singleton = new SquareState (true, 'O', 'o');
			states ~= singleton;
		}
		return singleton;
	}
	
	static SquareState p1 () {
		static SquareState singleton = null;
		if (singleton is null) {
			singleton = new SquareState (true, 'V', 'v');
			states ~= singleton;
		}
		return singleton;
	}
	
	static SquareState p2 () {
		static SquareState singleton = null;
		if (singleton is null) {
			singleton = new SquareState (true, 'R', 'r');
			states ~= singleton;
		}
		return singleton;
	}
	
	static SquareState move () {
		static SquareState singleton = null;
		if (singleton is null) {
			singleton = new SquareState (false, 'X', 'x');
			states ~= singleton;
		}
		return singleton;
	}
	
	// class functions
	static void initializeBeforeSearch () {
		empty ();
		hole ();
		p1 ();
		p2 ();
	}
	
	static SquareState makeFromSavesymbol (char c) {
		foreach (SquareState s; states) {
			if (s.savesymbol == c) {
				return s;
			}
		}
		return SquareState.empty;
	}
	
	// constructor
	this (bool pbusy, char psymbol, char psavesymbol) {
		_busy = pbusy;
		_symbol = psymbol;
		_savesymbol = psavesymbol;
	}
	
	// instance functions
	bool isBusy() {return _busy;}
	char symbol() {return _symbol;}
	char savesymbol() {return _savesymbol;}
}


class Grid {
private :
	SquareState[][] _tab;
public :
	this (int width, int height) {
		SquareState[] tmptab;
		
		tmptab.length = width;
		tmptab[0..$] = SquareState.empty;
		
		_tab.length = height;
		
		for (int i = 0; i < _tab.length; i++)
			_tab[i] = tmptab.dup;
	}
	
	this (char[] filename) {
		load (filename);
	}

	SquareState opIndex (int x, int y) {
		return _tab[y][x];
	}
	
	SquareState opIndexAssign (SquareState state, int x, int y) {
		return _tab[y][x] = state;
	}
	
	void move (Coord orig, Coord dest) {
		
	}
	
	void load (char[] filename) {
		auto f = new File (filename, FileMode.In);
		
		SquareState.initializeBeforeSearch;
		
		_tab.length = 0;
		
		foreach (string line; f) {
			_tab.length = _tab.length + 1;
			foreach (char c; line) {
				_tab[$-1].length = _tab[$-1].length + 1;
				_tab[$-1][$-1] = SquareState.makeFromSavesymbol (c);
			}
		}
		
		f.close;
	}
	
	void save (char[] filename) {
		auto f = new File (filename, FileMode.OutNew);
		
		foreach (SquareState[] states; _tab) {
			foreach (SquareState s; states)
				f.writef (s.savesymbol);
			f.writefln;
		}
		f.close;
	}
	
	
	string toString () {
		string str;
		
		foreach (SquareState[] states; _tab) {
			foreach (SquareState s; states)
				str ~= s.symbol;
			str ~= '\n';
		}
		
		return str;
	}
	
	int height () {
		return _tab.length;
	}
	
	int width () {
		return _tab[0].length;
	}
	
	void setPossibleMoves (SquareState state) {
		for (auto y = 0; y < height; y++)
		for (auto x = 0; x < width; x++) {
			if (!this[x, y].isBusy) {
				if (isMovePossible(x, y, state))
					this[x, y] = SquareState.move;
				else
					this[x, y] = SquareState.empty;
			}
		}
	}
	
private :
	bool isInside (int x, int y) {
		return (x >= 0 && x < width && y >=0 && y < height);
	}
	
	bool isMovePossible (int x, int y, SquareState state) {
		for (auto i = x - 1; i <= x + 1; i++)
		for (auto j = y - 1; j <= y + 1; j++) {
			
			//~ fprintf (stderr, "%i %i %i\n", i, j, isInside(i, j));
			if (isInside(i, j) && state == this[i, j])
				return true;
		}
		
		return ((isInside(x + 2, y) && state == this[x+2, y])
			|| (isInside(x, y + 2) && state == this[x, y+2])
			|| (isInside(x - 2, y) && state == this[x-2, y])
			|| (isInside(x, y - 2) && state == this[x, y-2]));
	}
}


class Point {
	int x;
	int y;
	/*
	this (int _x, int _y) {
		x = _x;
		y = _y;
	}
	*/
	this (int x, int y) {
		this.x = x;
		this.y = y;
	}
}

class Coord : Point {
	this (int _x, int _y) { super(_x, _y); }
}

class Move {
	Point a;
	Point b;
	this (int x1, int y1, int x2, int y2) {
		a = new Point(x1, y1);
		b = new Point(x2, y2);
	}
}

class Game {
private :
	Grid grid;
	bool turn;
public :
	this () {
		
	}
}
